import { ShapeFlags } from "../shared/shapeFlags";
import type { vnode, vnodeChildren, vnodeProps, vnodeType } from "./index.d"


/**创建虚拟节点
 * @param type 节点类型，element类型就是div等字符串，组件类型就是用户传入的对象
 * @param props 属性，键值对
 * @param children 孩子，可能是字符串或者vnode数组
 * @returns 虚拟节点
 */
export function createVNode(type: vnodeType, props?: vnodeProps, children?: vnodeChildren): vnode {
    const vnode: vnode = {
        type,
        component: null,
        props,
        key: props?.key,
        children,
        shapeFlag: getShapeFlag(type), // 根据 type 得到初始化的 shapeFlag 
        el: null
    }

    // 基于 children 再次设置 shapeFlag，下面使用了位运算，有关位运算的知识可以看 src\shared\shapeFlags.ts
    if (Array.isArray(children)) { //是数组就把数组那位变成1
        vnode.shapeFlag |= ShapeFlags.ARRAY_CHILDREN;
    } else if (typeof children === "string") {//是字符串就把字符串那位变成1
        vnode.shapeFlag |= ShapeFlags.TEXT_CHILDREN;
    }
    // 判断是否children是slot   1.自身是个组件、children是obj
    if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {//如果是组件类型
        if (typeof children === 'object') { //如果children还是个对象
            vnode.shapeFlag |= ShapeFlags.SLOTS_CHILDREN //那么就修改这个类型
        }
    }
    return vnode
}
/**基于 type 来初始化是什么类型的组件 */
function getShapeFlag(type: vnodeType) {
    return typeof type === "string" ? ShapeFlags.ELEMENT : ShapeFlags.STATEFUL_COMPONENT;
}

//用 symbol 作为唯一标识，避免写错，也可以避免用户写这个
/**文本类型的节点 */
export const Text = Symbol("Text");
/**Fragment类型的节点  特殊标签  - 只渲染children，自身不会出现在DOM中  */
export const Fragment = Symbol("Fragment");
// 其中还有几个类型比如： static fragment comment

/**创建text类型的vnode  （没有标签包裹） */
export function createTextVNode(text: string = " ") {
    return createVNode(Text, {}, text);
}